home *** CD-ROM | disk | FTP | other *** search
/ Just Call Me Internet / Just Call Me Internet.iso / prog / atari / c / nos042_s / sz.c < prev    next >
C/C++ Source or Header  |  1994-09-16  |  48KB  |  2,130 lines

  1. /****************************************************************************
  2. *    Language     :    Turbo C 2.0            
  3. *    Logfile        :    sz.c                    
  4. *    Project        :    Comms library.        
  5. *    Date         :    24 Jan 90                
  6. *    Revision     :    1.1        GT    PC version.                            
  7. *    07 Mar 90    :    1.2        GT    Background transfer.                
  8. *    25 Oct 92    :    1.3        GT    Mods for KA9Q.                        
  9. *    30 Jan 93    :    1.4        GT    Fix KA9Q background working.    
  10. *    21 Feb 93    :    1.5        GT    Fix reporting.                        
  11. *    08 May 93    :    1.6        GT    Fix warnings.                        
  12. *    24 Jan 94    :    1.7        GT    _flush -> _rbsb_flush.                    
  13. *****************************************************************************
  14. *    Purpose        :    File send driver.    
  15. *****************************************************************************
  16. *                :    This module is based on the equivalent module in the
  17. *                :    31 Aug 87 version of rz/sz.                                
  18. *    $Id: sz.c 1.5 94/01/26 13:55:15 ROOT_DOS Exp $
  19. *
  20. *  ATARI Version by David Nash - dnash@chaos.demon.co.uk
  21. *
  22. ****************************************************************************/
  23.  
  24. #include    <io.h>
  25. #include    <fcntl.h>
  26. #include    <stdio.h>
  27. #include    <stdlib.h>
  28. #include    <signal.h>
  29. #include    <setjmp.h>
  30. #include    <ctype.h>
  31. #include    <stdarg.h>
  32. #include    <time.h>
  33. #include    <process.h>
  34. #include    <string.h>
  35. #include    <io.h>
  36. #include    <sys/types.h>
  37. #include    <sys/stat.h>
  38. #include    <dos.h>
  39. #ifdef ATARI
  40. #include <ext.h>
  41. #endif
  42. #include "config.h"
  43. #include    "socket.h"
  44. #include    "proc.h"
  45.  
  46. /* kludge for krappy Microsoft */
  47.  
  48. #ifndef    S_IFBLK
  49. #define    S_IFBLK        0x3000
  50. #endif
  51.  
  52. #include    "zmodem.h"
  53. #include    "sz.h"
  54. #include    "rbsb.h"            /* most of the system dependent stuff here    */
  55. #include    "zm.h"
  56. #ifdef    DEBUGZ
  57. #include    "tty.h"
  58. #endif
  59.  
  60.  
  61. #define HOWMANY        2048
  62. #define    NO_DCD        1
  63.  
  64. /****************************************************************************
  65. *    Local prototypes.                                                        *
  66. ****************************************************************************/
  67.  
  68. #if    0
  69. static void bibi (int n);
  70. #endif
  71. static void chkinvok (char protocol);
  72. static int readline (int n);
  73. static void purgeline (void);
  74. #if    0
  75. static void onintr (void);
  76. #endif
  77. static int wcsend (int argc, char **argp);
  78. static int wcs (char *oname);
  79. static int wctxpn (char *name);
  80. static int getnak (void);
  81. static int wctx (long flen);
  82. static int wcputsec (char *buf, int sectnum, int cseclen);
  83. static int filbuf (char *buf, int count);
  84. static int zfilbuf (char *buf, int count);
  85. static int readock (int timeout, int count);
  86. static int getzrxinit (void);
  87. static int sendzsinit (void);
  88. static int zsendfile (char *buf, int blen);
  89. static int zsendfdata (void);
  90. static int getinsync (int flag);
  91. static void saybibi (void);
  92. static int zsendcmd (char *buf, int blen);
  93.  
  94.  
  95. /****************************************************************************
  96. *    Global data.                                                            *
  97. ****************************************************************************/
  98.  
  99. int _Zmodem = 0;                /* ZMODEM protocol requested                */
  100. unsigned _Baud_z = 19200;
  101. static unsigned Txwindow;        /* Control the size of the transmitted window */
  102. static unsigned Txwspac;        /* Spacing between zcrcq requests            */
  103. static unsigned Txwcnt;            /* Counter used to space ack requests        */
  104. static long Lrxpos;                /* Receiver's last reported offset            */
  105. int _errors;
  106. int _sending;                    /* TRUE - sending a file.                    */
  107. int _zperr_handle;                /* -> log file                                */
  108.  
  109. /*
  110.  * Attention string to be executed by receiver to interrupt streaming data
  111.  *  when an error is detected.  A pause (0336) may be needed before the
  112.  *  ^C (03) or after it.
  113.  */
  114.  
  115. static char Myattn[] = { 0 };
  116.  
  117. static int in;
  118.  
  119. int _Lastrx;                                /* was char                        */
  120. int _Crcflg;                                /* was char                        */
  121. int _Wcsmask = 0377;
  122.  
  123. /* Command line option flags */
  124.  
  125. int _Verbose = 0;
  126. static int Modem2 = 0;            /* XMODEM Protocol - don't send pathnames    */
  127. int _Quiet = 0;                    /* overrides logic that would otherwise set
  128.                                    verbose                                    */
  129. static int Ascii = 0;            /* Add CR's for brain damaged programs        */
  130. static int Fullname = 0;        /* transmit full pathname                    */
  131. static int Unlinkafter = 0;        /* Unlink file after it is sent                */
  132.  
  133. static int Dottoslash = 0;        /* Change foo.bar.baz to foo/bar/baz        */
  134. int _firstsec;
  135. static int errcnt = 0;            /* number of files unreadable                */
  136. static int blklen = SECSIZ;        /* length of transmitted records            */
  137. static int Optiong;                /* Let it rip no wait for sector ACK's        */
  138. static int Noeofseen;
  139. static int Totsecs;                /* total number of sectors this file        */
  140. static char txbuf[KSIZE];
  141. static int Filcnt = 0;            /* count of number of files opened            */
  142. static int Lfseen = 0;
  143. static unsigned Rxbuflen = 16384;    /* Receiver's max buffer length            */
  144. static int Tframlen = 0;        /* Override for tx frame length                */
  145. static int blkopt = 0;            /* Override value for zmodem blklen            */
  146. static int Rxflags = 0;
  147. static long bytcnt;
  148. static int Wantfcs32 = TRUE;    /* want to send 32 bit FCS                    */
  149. static char Lzconv;                /* Local ZMODEM file conversion request        */
  150. char _Lzmanag;                    /* Local ZMODEM file management request        */
  151. static int Lskipnocor;
  152. static char Lztrans;
  153. char _zconv;                    /* ZMODEM file conversion request            */
  154. char _zmanag;                    /* ZMODEM file management request            */
  155. char _ztrans;                    /* ZMODEM file transport request            */
  156. static int Command;                /* Send a command, then exit.                */
  157. static char Cmdstr[256];        /* Command string                            */
  158. static int Cmdtries = 11;
  159. static int Cmdack1;                /* Rx ACKs command, then do it                */
  160. static int Exitcode;
  161. static int Testattn;            /* Force receiver to send Attn, etc with qbf. */
  162. static char *qbf = "The quick brown fox jumped over the lazy dog's back "
  163.                    "1234567890\r\n";
  164. static long Lastread;            /* Beginning offset of last buffer read        */
  165. static int Lastn;                /* Count of last buffer read or -1            */
  166. static int Dontread;            /* Don't read the buffer, it's still there    */
  167. static long Lastsync;            /* Last offset to which we got a ZRPOS        */
  168. static int Beenhereb4;            /* How many times we've been ZRPOS'd same
  169.                                    place                                    */
  170.  
  171. jmp_buf _tohere;                    /* For user abort.                            */
  172. static jmp_buf intrjmp;            /* For the interrupt on RX CAN.                */
  173. jmp_buf _nocarrier;                /* For carrier dropped.                        */
  174.  
  175. int _Zctlesc;                    /* Encode control characters                */
  176. int _Nozmodem = 0;                /* If invoked as "sb"                        */
  177. int _Zrwindow = 1400;            /* RX window size (controls garbage count)    */
  178. void (*_do_report) (int type, void *data) = _zperr;
  179.                                 /* -> progress report fn                    */
  180.  
  181. extern int Lleft;                /* number of chars in read buffer            */
  182. extern int Readnum;                /* how many bytes to read                    */
  183.  
  184.  
  185. #if    0
  186. /****************************************************************************
  187. *    bibi                                                                    *
  188. *    Called by signal interrupt or terminate to clean things up.                *
  189. ****************************************************************************/
  190.  
  191. static void bibi (int n)
  192.     {
  193.     n = n;
  194.     _canit ();
  195.     _zperr_ ("Interrupted\n");
  196.     longjmp (_tohere, -1);
  197.     }    /* static void bibi (int n) */
  198.  
  199.  
  200. /****************************************************************************
  201. *    onintr                                                                    *
  202. *    Called when Zmodem gets an interrupt (^X).                                *
  203. ****************************************************************************/
  204.  
  205. static void onintr (void)
  206.     {
  207. #if    0
  208.     signal (SIGINT, SIG_IGN);
  209. #endif
  210.     longjmp (intrjmp, -1);
  211.     }    /* static void onintr (void) */
  212. #endif
  213.  
  214.  
  215. /****************************************************************************
  216. *    _no_carrier                                                                *
  217. *    Tests to see if CD still present, exits if not.                            *
  218. ****************************************************************************/
  219.  
  220. void _no_carrier (void)
  221.     {
  222. #if    !defined (NO_DCD)
  223.     if ((modemstat () & 0x80) == 0)
  224.         {
  225.         _zperr_ ("No carrier\n");
  226.         longjmp (_nocarrier, -1);
  227.         }
  228.  
  229. #endif
  230.     }    /* void _no_carrier (void) */
  231.     
  232.  
  233. /****************************************************************************
  234. *    _sendline and _xsendline                                                *
  235. *    Send a character to remote.                                                *
  236. ****************************************************************************/
  237.  
  238. void _sendline (int c)
  239.     {
  240.     if (_sending)
  241.         c &= _Wcsmask;
  242.  
  243.     _xsendline (c);
  244.     }    /* void _sendline (int c) */
  245.  
  246.  
  247. void _xsendline (int c)
  248.     {
  249. #ifdef    DEBUGZ
  250.     if (_Verbose > 6)
  251.         _vfile ("_xsendline: %x\n", c);
  252. #endif
  253.  
  254.     while (_send ((unsigned char *) &c, 1) != 1)
  255.         _no_carrier ();
  256.         
  257.     }    /* void _xsendline (int c) */
  258.     
  259.  
  260. /****************************************************************************
  261. *    _flushmo                                                                *
  262. *    Flush the ouput channel.                                                *
  263. ****************************************************************************/
  264.  
  265. void _flushmo (void)
  266.     {
  267.     _rbsb_flush ();
  268.     }    /* void _flushmo (void) */
  269.  
  270.  
  271. /****************************************************************************
  272. *    _sendfile                                                                *
  273. *    Send file(s).  Returns 0 if successful.                                    *
  274. ****************************************************************************/
  275.  
  276. int _sendfile (int s, char protocol, char *options, char *filenames[],
  277.                void (*reporter) (int type, void *data))
  278.     {
  279.     char *cp;
  280.     int npats;
  281.     int agcnt;
  282.     char **agcv;
  283.     char **patts;
  284.     int i;                                    /* loop counter                    */
  285. #if    0
  286.     void (*sigint_sav) (int);
  287.     void (*sigterm_sav) (int);
  288. #endif
  289.     
  290.     /* Initialise global variables */
  291.  
  292.     _z_socket = s;
  293.     Lleft = 0;
  294.     Readnum = HOWMANY;
  295.     Ascii = 0;
  296.     blklen = SECSIZ;
  297.     blkopt = 0;
  298.     Cmdtries = 11;
  299.     Command = FALSE;
  300.     _do_report = _zperr;
  301.     Dottoslash = 0;
  302.     errcnt = 0;
  303.     Exitcode = 0;
  304.     Filcnt = 0;
  305.     Fullname = 0;
  306.     Lfseen = 0;
  307.     Modem2 = 0;
  308.     _Nozmodem = 0;
  309.     _Quiet = 0;
  310.     Rxbuflen = 16384;
  311.     Rxflags = 0;
  312.     _sending = TRUE;
  313.     Tframlen = 0;
  314.     Unlinkafter = 0;
  315.     Wantfcs32 = TRUE;
  316.     _Wcsmask = 0377;
  317.     _Verbose = 0;
  318.     _Zmodem = 0;
  319.     _Zrwindow = 1400;
  320.  
  321.     /* See if null padding required */
  322.     
  323.     if (((cp = getenv ("ZNULLS")) != NULL) && *cp)
  324.         _Znulls = atoi (cp);
  325.     
  326.     chkinvok (protocol);                    /* select protocol                */
  327.     _Rxtimeout = 600;
  328.     npats = 0;
  329.  
  330.     /* Parse options. */
  331.     
  332.     cp = options;
  333.     while (*cp != '\0')
  334.         {
  335.         switch (*cp++)
  336.             {
  337.             case '+':                        /* append file                    */
  338.                 _Lzmanag = ZMAPND;
  339.                 break;
  340.  
  341.             case '7':                        /* strip top bit                */
  342.                 _Wcsmask = 0177;
  343.                 break;
  344.  
  345.             case 'a':                        /* NL -> CRNL conversion        */
  346.                 Lzconv = ZCNL;
  347.                 Ascii = TRUE;
  348.                 break;
  349.  
  350.             case 'b':                        /* binary file                    */
  351.                 Lzconv = ZCBIN;
  352.                 break;
  353.  
  354.             case 'i':                        /* command, no wait                */
  355.                 Cmdack1 = ZCACK1;
  356.  
  357.                 /* **** FALL THROUGH TO **** */
  358.  
  359.             case 'c':                        /* command, wait                */
  360.                 if (*cp != '#')                /* command delimiter?            */
  361.                     return (ERROR);            /* invalid parameter            */
  362.  
  363.                 Command = TRUE;
  364.                 for (i = 0; i < sizeof (Cmdstr); i++)
  365.                     {
  366.                     if (*++cp == '#')
  367.                         break;                /* end of command                */
  368.                         
  369.                     Cmdstr[i] = *cp;
  370.                     }
  371.  
  372.                 Cmdstr[i] = '\0';
  373.                 cp++;
  374.                 break;
  375.                 
  376.             case 'd':                        /* . -> /                        */
  377.                 ++Dottoslash;
  378.                 
  379.                 /* **** FALL THROUGH TO **** */
  380.  
  381.             case 'f':                        /* full pathnames                */
  382.                 Fullname = TRUE;
  383.                 break;
  384.             
  385.             case 'e':                        /* escape ctl chars                */
  386.                 _Zctlesc = 1;
  387.                 break;
  388.  
  389.             case 'k':                        /* YMODEM 1k                    */
  390.                 blklen = KSIZE;
  391.                 break;
  392.  
  393.             case 'L':                        /* limit subpacket length        */
  394.                 sscanf (cp, "%d", &blkopt);
  395.                 if (blkopt < 24 || blkopt > 1024)
  396.                     return (ERROR);            /* bad length                    */
  397.  
  398.                 cp = _stbnb (cp);            /* skip whitespace                */
  399.                 break;
  400.                 
  401.             case 'l':                        /* limit frame length            */
  402.                 sscanf (cp, "%d", &Tframlen);
  403.                 if (Tframlen < 32 || Tframlen > 1024)
  404.                     return (ERROR);
  405.  
  406.                 cp = _stbnb (cp);
  407.                 break;
  408.                 
  409.             case 'N':                        /* source newer or longer        */
  410.                 _Lzmanag = ZMNEWL;
  411.                 break;
  412.                 
  413.             case 'n':                        /* source newer                    */
  414.                 _Lzmanag = ZMNEW;
  415.                 break;
  416.                 
  417.             case 'o':                        /* 16 bit CRC                    */
  418.                 Wantfcs32 = FALSE;
  419.                 break;
  420.  
  421.             case 'p':                        /* no target overwrite            */
  422.                 _Lzmanag = ZMPROT;
  423.                 break;
  424.  
  425.             case 'r':                        /* resume file transfer            */
  426.                 Lzconv = ZCRESUM;
  427.                 break;
  428.  
  429.             case 'q':                        /* quiet                        */
  430.                 _Quiet = TRUE;
  431.                 _Verbose = 0;
  432.                 break;
  433.  
  434.             case 't':                        /* change timeout                */
  435.                 sscanf (cp, "%d", &_Rxtimeout);
  436.                 if (_Rxtimeout < 10 || _Rxtimeout > 1000)
  437.                     return (ERROR);
  438.  
  439.                 cp = _stbnb (cp);
  440.                 break;
  441.  
  442.             case 'T':                        /* test attention mode            */
  443.                 Testattn = TRUE;
  444.                 break;
  445.  
  446.             case 'u':                        /* erase after send                */
  447.                 ++Unlinkafter;
  448.                 break;
  449.                 
  450.             case 'v':                        /* debugging info                */
  451.                 ++_Verbose;
  452.                 break;
  453.                 
  454.             case 'w':                        /* window size                    */
  455.                 sscanf (cp, "%d", &Txwindow);
  456.                 if (Txwindow < 256)
  457.                     Txwindow = 256;
  458.                     
  459.                 Txwindow = (Txwindow / 64) * 64;
  460.                 Txwspac = Txwindow / 4;
  461.                 if (blkopt > Txwspac || (!blkopt && Txwspac < 1024))
  462.                     blkopt = Txwspac;
  463.                     
  464.                 cp = _stbnb (cp);
  465.                 break;
  466.                 
  467.             case 'X':                        /* use XMODEM                    */
  468.                 ++Modem2;
  469.                 break;
  470.                 
  471.             case 'Y':                        /* overwrite target only if
  472.                                                present                        */
  473.                 Lskipnocor = TRUE;
  474.  
  475.                 /* **** FALL THROUGH TO **** */
  476.  
  477.             case 'y':                        /* overwrite target always        */
  478.                 _Lzmanag = ZMCLOB;
  479.                 break;
  480.  
  481.             default:
  482.                 return (ERROR);
  483.             }    /* switch (*cp++) */
  484.  
  485.         }    /* while (*cp != '\0') */
  486.  
  487.     /* parse filenames */
  488.  
  489.     patts = filenames;
  490.     while (**patts != '\0')
  491.         {
  492.         npats++;                            /* bump filename count            */
  493.         patts++;                            /* try next string                */
  494.         }
  495.  
  496.     patts = filenames;
  497.     if (npats < 1 && !Command) 
  498.         return (ERROR);                        /* no filenames                    */
  499.  
  500.     /* Get reporter function */
  501.  
  502.     if (reporter != NULL)
  503.         _do_report = reporter;                /* user supplied fn                */
  504.  
  505. #if    0
  506.     if (_Verbose)
  507.         {
  508.         if ((_zperr_handle = open (LOGFILE,
  509.                                    O_CREAT | O_APPEND | O_WRONLY | O_TEXT,
  510.                                    S_IFREG | S_IWRITE)) == -1)
  511.             {
  512.             char buff[80];
  513.             
  514.             sprintf (buff, "Can't open log file %s: %s\n",
  515.                      LOGFILE, strerror (errno));
  516.             (*_do_report) (2, buff);
  517.             (*_do_report) (3, &Filcnt);        /* report no of files            */
  518.         
  519.             return (ERROR);
  520.             }
  521.  
  522.         _do_report = _zperr;                /* use default reporter            */
  523.         }
  524. #endif
  525.     
  526.     if (!_Quiet)
  527.         {
  528.         if (_Verbose == 0)
  529.             _Verbose = 2;
  530.             
  531.         }
  532.  
  533. #if    0
  534.     if ((sigint_sav = signal (SIGINT, bibi)) == SIG_IGN)
  535.         signal (SIGINT, SIG_IGN);
  536.     else
  537.         signal (SIGINT, bibi);
  538.  
  539. #endif
  540.  
  541. #if    0
  542.     sigint_sav = signal (SIGINT, bibi);
  543.     sigterm_sav = signal (SIGTERM, bibi);
  544. #endif
  545.         
  546.     /* Organise escape routes. */
  547.  
  548.     if (setjmp (_tohere) != 0)
  549.         {
  550.         (*_do_report) (3, &Filcnt);            /* report no of files            */
  551. #if    0
  552.         signal (SIGINT, sigint_sav);
  553.         signal (SIGTERM, sigterm_sav);
  554.         (void) close (_zperr_handle);
  555. #endif
  556.         return (-2);                        /* user abort                    */
  557.         }
  558.  
  559.     if (setjmp (_nocarrier) != 0)
  560.         {
  561.         (*_do_report) (3, &Filcnt);            /* report no of files            */
  562. #if    0
  563.         signal (SIGINT, sigint_sav);
  564.         signal (SIGTERM, sigterm_sav);
  565.         (void) close (_zperr_handle);
  566. #endif
  567.         return (-3);                        /* lost carrier                    */
  568.         }
  569.  
  570.     if (!Modem2)
  571.         {
  572. #if    0
  573.         if (!_Nozmodem)
  574.             {
  575.             printf ("rz\r");
  576.             }
  577. #endif
  578.  
  579.         if (!Command && !_Quiet && _Verbose != 1)
  580.             {
  581.             _say ("%d file%s requested:\r\n",
  582.                      npats, npats > 1 ? "s" : "");
  583.             for (agcnt = npats, agcv = patts; --agcnt >= 0;)
  584.                 {
  585.                 _say ("%s ", *agcv++);
  586.                 }
  587.                 
  588.             _say ("\r\n");
  589.             _say ("\r\n\bSending in Batch Mode\r\n");
  590.             }
  591.             
  592.         if (!_Nozmodem)
  593.             {
  594.             _stohdr (0L);
  595.             if (Command)
  596.                 _Txhdr[ZF0] = ZCOMMAND;
  597.  
  598.             _zshhdr (ZRQINIT, _Txhdr);
  599.             }
  600.  
  601.         }    /* if (!Modem2) */
  602.         
  603.     if (Command)
  604.         {
  605.         if (getzrxinit ())
  606.             {
  607.             Exitcode = -2;
  608.             _canit ();
  609.             }
  610.         else if (zsendcmd (Cmdstr, 1 + strlen (Cmdstr)))
  611.             {
  612.             Exitcode = -2;
  613.             _canit ();
  614.             }
  615.             
  616.         }
  617.     else if (wcsend (npats, patts) == ERROR)
  618.         {
  619.         Exitcode = -2;
  620.         _canit ();
  621.         }
  622.         
  623.     if (!_Quiet)
  624.         _say ("\n");
  625.  
  626.     (*_do_report) (3, &Filcnt);            /* report no of files            */
  627. #if    0
  628.     signal (SIGINT, sigint_sav);
  629.     signal (SIGTERM, sigterm_sav);
  630.     (void) close (_zperr_handle);
  631. #endif
  632.     return (Exitcode);
  633.     }    /* int _sendfile (int s, char protocol, char *options,
  634.                           char *filenames[],
  635.                           void (*reporter) (int type, void *data)) */
  636.  
  637.  
  638. /****************************************************************************
  639. *    _stbnb                                                                    *
  640. *    Skip to blank then skip to nonblank.                                    *
  641. ****************************************************************************/
  642.  
  643. char *_stbnb (char *cp)
  644.     {
  645.     /* skip to blank */
  646.  
  647.     while (!isspace (*cp))
  648.         cp++;
  649.         
  650.     /* skip to nonblank */
  651.  
  652.     while (isspace (*cp))
  653.         cp++;
  654.  
  655.     return (cp);
  656.     }    /* char *_stbnb (char *cp) */
  657.  
  658.  
  659. /****************************************************************************
  660. *    wcsend                                                                    *
  661. *    Send <argc> strings (<argp>) to remote.                                    *
  662. ****************************************************************************/
  663.  
  664. static int wcsend (int argc, char **argp)
  665.     {
  666.     int n;
  667.  
  668.     _Crcflg = FALSE;
  669.     _firstsec = TRUE;
  670.     bytcnt = -1;
  671.     for (n = 0; n < argc; ++n)
  672.         {
  673.         Totsecs = 0;
  674.         if (wcs (argp[n]) == ERROR)
  675.             return ERROR;
  676.             
  677.         }
  678.         
  679.     Totsecs = 0;
  680.     if (Filcnt == 0)
  681.         {
  682.         /* bitch if we couldn't open ANY files */
  683.         
  684. #if    0
  685.         if (1)
  686. #endif
  687.             {
  688.             Command = TRUE;
  689.             strcpy (Cmdstr, "echo Can't open any requested files");
  690.             if (getnak ())
  691.                 {
  692.                 Exitcode = -2;
  693.                 _canit ();
  694.                 }
  695.                 
  696.             if (!_Zmodem)
  697.                 _canit ();
  698.             else if (zsendcmd (Cmdstr, 1 + strlen (Cmdstr)))
  699.                 {
  700.                 Exitcode = -2;
  701.                 _canit ();
  702.                 }
  703.                 
  704.             Exitcode = -2;
  705.             return OK;
  706.             }
  707.             
  708. #if    0                                    /* unreachable                        */
  709.         _canit ();
  710.         _say ("\r\nCan't open any requested files.\r\n");
  711.         return ERROR;
  712. #endif
  713.         }    /* if (Filcnt == 0) */
  714.         
  715.     if (_Zmodem)
  716.         saybibi ();
  717.     else if (!Modem2)
  718.         wctxpn ("");
  719.         
  720.     return OK;
  721.     }    /* static int wcsend (int argc, char **argp) */
  722.  
  723.  
  724. /****************************************************************************
  725. *    wcs                                                                        *
  726. *    Send file <oname> to remote.                                            *
  727. ****************************************************************************/
  728.  
  729. static int wcs (char *oname)
  730.     {
  731.     int c;
  732.     struct stat f;
  733.     char name[PATHLEN];
  734.  
  735.     strcpy (name, oname);
  736.     if ((in = open (oname, O_RDONLY | O_BINARY, S_IREAD)) == -1)
  737.         {
  738.         if (_Verbose > 2)
  739.             {
  740.             _say ("Couldn't open %s\r\n", oname);
  741.             }
  742.             
  743.         ++errcnt;
  744.         return OK;    /* pass over it, there may be others */
  745.         }
  746.         
  747.     ++Noeofseen;
  748.     Lastread = 0;
  749.     Lastn = -1;
  750.     Dontread = FALSE;
  751.     
  752.     /* Check for directory or block special files */
  753.     
  754.     fstat (in, &f);
  755.     c = f.st_mode & S_IFMT;
  756.     if (c == S_IFDIR || c == S_IFBLK)
  757.         {
  758.         close (in);
  759.         return OK;
  760.         }
  761.  
  762.     ++Filcnt;
  763.     switch (wctxpn (name))
  764.         {
  765.         case ERROR:
  766.             return ERROR;
  767.             
  768.         case ZSKIP:
  769.             return OK;
  770.         }
  771.         
  772.     if (!_Zmodem && wctx (f.st_size) == ERROR)
  773.         return ERROR;
  774.         
  775.     if (Unlinkafter)
  776.         unlink (oname);
  777.         
  778.     return 0;
  779.     }    /* static int wcs (char *oname) */
  780.     
  781.  
  782. /****************************************************************************
  783. *    wctxpn                                                                    *
  784. *    Generate and transmit pathname block consisting of pathname (null         *
  785. *    terminated), file length, mode time and file mode in octal as provided     *
  786. *    by the fstat call.                                                        *
  787. *    N.B.: modifies the passed name, may extend it!                            *
  788. ****************************************************************************/
  789.  
  790. static int wctxpn (char *name)
  791.     {
  792.     char *p, *q;
  793.     char name2[PATHLEN];
  794.     struct stat f;
  795.  
  796.     (*_do_report) (0, name);
  797.     if (Modem2)
  798.         {
  799.         if (*name && (fstat (in, &f) != -1))
  800.             {
  801.             _say ("Sending %s, %ld blocks: ", name, f.st_size >> 7);
  802.             }
  803.  
  804.         _say ("Give your local XMODEM receive command now.\r\n");
  805.         return OK;
  806.         }
  807.  
  808.     _vfile ("Awaiting pathname nak for %s", *name ? name : "<END>");
  809.     if (!_Zmodem)
  810.         if (getnak ())
  811.             return ERROR;
  812.             
  813.     q = (char *) 0;
  814.     if (Dottoslash)
  815.         {
  816.         /* change . to . */
  817.         for (p = name; *p; ++p)
  818.             {
  819.             if (*p == '/')
  820.                 q = p;
  821.             else if (*p == '.')
  822.                 *(q = p) = '/';
  823.                 
  824.             }
  825.             
  826.         if (q && strlen (++q) > 8)
  827.             {
  828.             /* If name > 8 chars */
  829.             q += 8;                            /*   make it .ext                 */
  830.             strcpy (name2, q);                /* save excess of name             */
  831.             *q = '.';
  832.             strcpy (++q, name2);            /* add it back                     */
  833.             }
  834.             
  835.         }    /* if (Dottoslash) */
  836.  
  837.     for (p = name, q = txbuf; *p;)
  838.         if ((*q++ = *p++) == '\\' && !Fullname)
  839.             q = txbuf;
  840.             
  841.     *q++ = 0;
  842.     p = q;
  843.     while (q < (txbuf + KSIZE))
  844.         *q++ = 0;
  845.  
  846.     if (!Ascii && *name && fstat (in, &f) != -1)
  847.         sprintf (p, "%lu %lo %o", f.st_size, f.st_mtime, f.st_mode);
  848.         
  849.     /* force 1k blocks if name won't fit in 128 byte block */
  850.  
  851.     if (txbuf[125])
  852.         blklen = KSIZE;
  853.     else
  854.         {
  855.         /* A little goodie for IMP/KMD */
  856.         
  857.         if (_Zmodem)
  858.             blklen = SECSIZ;
  859.             
  860.         txbuf[127] = (char) ((f.st_size + 127) >> 7);
  861.         txbuf[126] = (char) ((f.st_size + 127) >> 15);
  862.         }
  863.         
  864.     if (_Zmodem)
  865.         return zsendfile (txbuf, (int) (1 + strlen (p) + (p - txbuf)));
  866.         
  867.     if (wcputsec (txbuf, 0, SECSIZ) == ERROR)
  868.         return ERROR;
  869.         
  870.     return OK;
  871.     }    /* static int wctxpn (char *name) */
  872.  
  873.  
  874. /****************************************************************************
  875. *    getnak                                                                    *
  876. *    Returns FALSE if NAK or ZPAD received.                                    *
  877. ****************************************************************************/
  878.  
  879. static int getnak (void)
  880.     {
  881.     int firstch;
  882.  
  883.     _Lastrx = 0;
  884.     for (;;)
  885.         {
  886.         switch (firstch = readock (800, 1))
  887.             {
  888.             case ZPAD:
  889.                 if (getzrxinit ())
  890.                     return ERROR;
  891.  
  892.                 Ascii = 0;
  893.                 return FALSE;
  894.                 
  895.             case ZTIMEOUT:
  896.                 _zperr_ ("Timeout on pathname");
  897.                 return TRUE;
  898.                 
  899.             case WANTG:
  900.                 Optiong = TRUE;
  901.                 blklen=KSIZE;
  902.                 
  903.             case WANTCRC:
  904.                 _Crcflg = TRUE;
  905.                 
  906.             case NAK:
  907.                 return FALSE;
  908.  
  909.             case CAN:
  910.                 if ((firstch = readock (20, 1)) == CAN && _Lastrx == CAN)
  911.                     return TRUE;
  912.                     
  913.             default:
  914.                 break;
  915.             }    /* switch (firstch = readock (800, 1)) */
  916.             
  917.         _Lastrx = firstch;
  918.         }    /* for (;;) */
  919.         
  920.     }    /* static int getnak (void) */
  921.     
  922.  
  923. /****************************************************************************
  924. *    wctx                                                                    *
  925. *    Send <flen> bytes (in blocks) using XMODEM or YMODEM.                    *
  926. ****************************************************************************/
  927.  
  928. static int wctx (long flen)
  929.     {
  930.     int thisblklen;
  931.     int sectnum, attempts, firstch;
  932.     long charssent;
  933.  
  934.     charssent = 0;
  935.     _firstsec = TRUE;
  936.     thisblklen = blklen;
  937.     _vfile ("wctx:file length = %ld", flen);
  938.  
  939.     while ((firstch = readock (_Rxtimeout, 2)) != NAK &&
  940.            firstch != WANTCRC &&
  941.            firstch != WANTG &&
  942.            firstch != ZTIMEOUT &&
  943.            firstch != CAN)
  944.         ;
  945.         
  946.     if (firstch == CAN)
  947.         {
  948.         _zperr_ ("Receiver CANcelled");
  949.         return ERROR;
  950.         }
  951.         
  952.     if (firstch == WANTCRC)
  953.         _Crcflg = TRUE;
  954.         
  955.     if (firstch == WANTG)
  956.         _Crcflg = TRUE;
  957.  
  958.     sectnum = 0;
  959.     for (;;)
  960.         {
  961.         if (flen <= (charssent + 896L))
  962.             thisblklen = 128;
  963.  
  964.         if (!filbuf (txbuf, thisblklen))
  965.             break;
  966.             
  967.         if (wcputsec (txbuf, ++sectnum, thisblklen) == ERROR)
  968.             return ERROR;
  969.             
  970.         charssent += thisblklen;
  971.         }
  972.  
  973.     close (in);
  974.     attempts = 0;
  975.     do
  976.         {
  977.         purgeline ();
  978.         _sendline (EOT);
  979.         ++attempts;
  980.         firstch = (readock (_Rxtimeout, 1));
  981.         } while (firstch != ACK && attempts < RETRYMAX);
  982.                  
  983.     if (attempts == RETRYMAX)
  984.         {
  985.         _zperr_ ("No ACK on EOT");
  986.         return ERROR;
  987.         }
  988.     else
  989.         return OK;
  990.  
  991.     }    /* static int wctx (long flen) */
  992.  
  993.  
  994. /****************************************************************************
  995. *    wcputsec                                                                *
  996. *    Send block <sectnum> of length <cseclen> using XMODEM or YMODEM.        *
  997. ****************************************************************************/
  998.  
  999. static int wcputsec (char *buf, int sectnum, int cseclen)
  1000.     {
  1001.     int checksum, wcj;
  1002.     char *cp;
  1003.     unsigned oldcrc;
  1004.     int firstch;
  1005.     int attempts;
  1006.  
  1007.     firstch = 0;                        /* part of logic to detect CAN CAN    */
  1008.  
  1009.     _vfile ("Sector %3d %2dk\n", Totsecs, Totsecs / 8 );
  1010.     if (_Verbose > 1)
  1011.         _say ("\rSector %3d %2dk ", Totsecs, Totsecs / 8 );
  1012.  
  1013.     for (attempts = 0; attempts <= RETRYMAX; attempts++)
  1014.         {
  1015.         _Lastrx = firstch;
  1016.         _sendline (cseclen == KSIZE ? STX : SOH);
  1017.         _sendline (sectnum);
  1018.         _sendline (- sectnum - 1);
  1019.         oldcrc = checksum = 0;
  1020.         for (wcj = cseclen, cp = buf; --wcj >= 0;)
  1021.             {
  1022.             _sendline (*cp);
  1023.             oldcrc = updcrc ((0377 & *cp), oldcrc);
  1024.             checksum += *cp++;
  1025.             }
  1026.             
  1027.         if (_Crcflg)
  1028.             {
  1029.             oldcrc = updcrc (0, updcrc (0, oldcrc));
  1030.             _sendline ((int) oldcrc >> 8);
  1031.             _sendline ((int) oldcrc);
  1032.             }
  1033.         else
  1034.             _sendline (checksum);
  1035.  
  1036.         if (Optiong)
  1037.             {
  1038.             _firstsec = FALSE;
  1039.             return OK;
  1040.             }
  1041.  
  1042.         firstch = readock (_Rxtimeout, (Noeofseen && sectnum) ? 2 : 1);
  1043.  
  1044. gotnak:
  1045.         switch (firstch)
  1046.             {
  1047.             case CAN:
  1048.                 if (_Lastrx == CAN)
  1049.                     {
  1050. cancan:
  1051.                     _zperr_ ("Cancelled");
  1052.                     return ERROR;
  1053.                     }
  1054.  
  1055.                 break;
  1056.  
  1057.             case ZTIMEOUT:
  1058.                 _zperr_ ("Timeout on sector ACK");
  1059.                 continue;
  1060.  
  1061.             case WANTCRC:
  1062.                 if (_firstsec)
  1063.                     _Crcflg = TRUE;
  1064.  
  1065.             case NAK:
  1066.                 _zperr_ ("NAK on sector");
  1067.                 continue;
  1068.  
  1069.             case ACK: 
  1070.                 _firstsec = FALSE;
  1071.                 Totsecs += (cseclen >> 7);
  1072.                 return OK;
  1073.  
  1074.             case ERROR:
  1075.                 _zperr_ ("Got burst for sector ACK");
  1076.                 break;
  1077.  
  1078.             default:
  1079.                 _zperr_ ("Got %02x for sector ACK", firstch);
  1080.                 break;
  1081.             }    /* switch (firstch) */
  1082.             
  1083.         for (;;)
  1084.             {
  1085.             _Lastrx = firstch;
  1086.             if ((firstch = readock (_Rxtimeout, 2)) == ZTIMEOUT)
  1087.                 break;
  1088.  
  1089.             if (firstch == NAK || firstch == WANTCRC)
  1090.                 goto gotnak;
  1091.  
  1092.             if (firstch == CAN && _Lastrx == CAN)
  1093.                 goto cancan;
  1094.  
  1095.             }
  1096.  
  1097.         }    /* for (attempts = 0; attempts <= RETRYMAX; attempts++) */
  1098.         
  1099.     _zperr_ ("Retry Count Exceeded");
  1100.     return ERROR;
  1101.     }    /* static int wcputsec (char *buf, int sectnum, int cseclen) */
  1102.     
  1103.  
  1104. /****************************************************************************
  1105. *    filbuf                                                                    *
  1106. *    Fill <buf> with <count> chars padding with ^Z for CPM.                    *
  1107. ****************************************************************************/
  1108.  
  1109. static int filbuf (char *buf, int count)
  1110.     {
  1111.     int c, m;
  1112.     char locbuf[BUFSIZ];                /* local read buffer                */
  1113.     char *q;                            /* -> read buffer                    */
  1114.     int rcount;                            /* no of chars read                    */
  1115.     
  1116.     if (!Ascii)
  1117.         {
  1118.         m = read (in, buf, count);
  1119.         if (m <= 0)
  1120.             return 0;
  1121.             
  1122.         while (m < count)
  1123.             buf[m++] = 032;
  1124.             
  1125.         return count;
  1126.         }
  1127.         
  1128.     m = count;
  1129.     if (Lfseen)
  1130.         {
  1131.         *buf++ = 012;
  1132.         --m;
  1133.         Lfseen = 0;
  1134.         }
  1135.         
  1136. #if    0
  1137.     while ((c = getc (in)) != EOF)
  1138. #endif
  1139.     while ((rcount = read (in, locbuf, sizeof (locbuf))) != -1)
  1140.         {
  1141.         q = locbuf;
  1142.         while (rcount-- != 0)
  1143.             {
  1144.             c = *q++;
  1145.             if (c == 012)
  1146.                 {
  1147.                 *buf++ = 015;
  1148.                 if (--m == 0)
  1149.                     {
  1150.                     Lfseen = TRUE;
  1151.                     break;
  1152.                     }
  1153.  
  1154.                 }
  1155.  
  1156.             *buf++ = (char) c;
  1157.             if (--m == 0)
  1158.                 break;
  1159.  
  1160.             }    /* while (rcount-- != 0) */
  1161.  
  1162.         if (m == 0)
  1163.             break;
  1164.  
  1165.         }    /* while ((rcount = read (in, locbuf, sizeof (locbuf)) != -1) */
  1166.  
  1167.     if (m == count)
  1168.         return 0;
  1169.     else
  1170.         while (--m >= 0)
  1171.             *buf++ = CPMEOF;
  1172.  
  1173.     return count;
  1174.     }    /* static int filbuf (char *buf, int count) */
  1175.     
  1176.  
  1177. /****************************************************************************
  1178. *    zfilbuf                                                                    *
  1179. *    Fill <buf> with <count> chars.                                            *
  1180. ****************************************************************************/
  1181.  
  1182. static int zfilbuf (char *buf, int count)
  1183.     {
  1184. #ifndef ATARI        
  1185.     if (eof (in))
  1186.         return (0);
  1187. #endif
  1188.         
  1189.     return (read (in, buf, count));
  1190. #if    0
  1191.     int c, m;
  1192.  
  1193.     m = count;
  1194.     while ((c = getc (in)) != EOF)
  1195.         {
  1196.         *buf++ = c;
  1197.         if (--m == 0)
  1198.             break;
  1199.  
  1200.         }
  1201.  
  1202.     return (count - m);
  1203. #endif
  1204.     }    /* static int zfilbuf (char *buf, int count) */
  1205.     
  1206.  
  1207. /****************************************************************************
  1208. *    _vfile                                                                    *
  1209. *    Print debugging message.                                                *
  1210. ****************************************************************************/
  1211.  
  1212. void _vfile (char *f, ...)
  1213.     {
  1214.     va_list parms;                            /* -> variable arguments        */
  1215.     char buf[128];                            /* for text                        */
  1216.     
  1217.     va_start (parms, f);
  1218.     if (_Verbose > 2)
  1219.         {
  1220.         vsprintf (buf, f, parms);
  1221.         strcat (buf, "\n");
  1222.         (*_do_report) (2, buf);                /* call reporter function        */
  1223.         }
  1224.  
  1225.     va_end (parms);
  1226.     }    /* void _vfile (char *f, ...) */
  1227.  
  1228.  
  1229. /****************************************************************************
  1230. *    _say                                                                    *
  1231. *    Report something unconditionally.                                        *
  1232. ****************************************************************************/
  1233.  
  1234. void _say (char *f, ...)
  1235.     {
  1236.     va_list parms;                            /* -> variable arguments        */
  1237.     char buf[128];                            /* for text                        */
  1238.     
  1239.     va_start (parms, f);
  1240.     vsprintf (buf, f, parms);
  1241.     (*_do_report) (2, buf);                    /* call reporter function        */
  1242.     va_end (parms);
  1243.     }    /* void say (char *f, ...) */
  1244.  
  1245.  
  1246. /****************************************************************************
  1247. *    readock                                                                    *
  1248. *    Reads character(s) from receive channel.  It attempts to read count     *
  1249. *    characters (1 <= <count> <= 3).  If it gets more than one, it is an     *
  1250. *    error unless all are CAN (otherwise, only normal response is ACK, CAN    *
  1251. *    or C).  Only looks for one if Optiong, which signifies cbreak, not raw     *
  1252. *    input.  <timeout> is in tenths of seconds.                                *
  1253. ****************************************************************************/
  1254.  
  1255. static int readock (int timeout, int count)
  1256.     {
  1257.     int c, t;
  1258.     static unsigned char byt[5];
  1259.     time_t start;                            /* start time for timeout        */
  1260.     
  1261.     if (Optiong)
  1262.         count = 1;                            /* Special hack for cbreak         */
  1263.  
  1264.     t = timeout / 10;
  1265.     if (t < 2)
  1266.         t = 2;
  1267.  
  1268.     time (&start);
  1269.     if (_Verbose > 5)
  1270.         {
  1271.         _say ("Timeout=%d Calling alarm (%d) ", timeout, t);
  1272.         byt[1] = 0;
  1273.         }
  1274.  
  1275.     _no_carrier ();
  1276.     while (1)
  1277.         {
  1278.         c = _receive (byt, count);
  1279.         if (c != 0)
  1280.             break;                            /* got something                */
  1281.  
  1282.         if (time (NULL) >= start + t)
  1283.             {
  1284.             _zperr_ ("TIMEOUT");
  1285.             return ZTIMEOUT;
  1286.             }
  1287.  
  1288.         }
  1289.         
  1290.     if (_Verbose > 5)
  1291.         _say ("ret cnt=%d %x %x\n", c, byt[0], byt[1]);
  1292.         
  1293.     if (c < 1)
  1294.         return ZTIMEOUT;
  1295.  
  1296.     if (c == 1)
  1297.         return (byt[0] & 0377);
  1298.     else
  1299.         while (c)
  1300.             if (byt[--c] != CAN)
  1301.                 return ERROR;
  1302.                 
  1303.     return CAN;
  1304.     }    /* static int readock (int timeout, int count) */
  1305.  
  1306.     
  1307. /****************************************************************************
  1308. *    readline                                                                *
  1309. *    Receive one control character with timeout.                                *
  1310. ****************************************************************************/
  1311.  
  1312. static int readline (int n)
  1313.     {
  1314.     return (readock (n, 1));
  1315.     }    /* static int readline (int n) */
  1316.     
  1317.  
  1318. /****************************************************************************
  1319. *    purgeline                                                                *
  1320. *    Flush input buffer.                                                        *
  1321. ****************************************************************************/
  1322.  
  1323. static void purgeline (void)
  1324.     {
  1325.     unsigned char c;
  1326.  
  1327.     while (_rdchk () > 0)
  1328.         _receive (&c, 1);
  1329.         
  1330. #if    0
  1331.     while (_receive (&c, 1) > 0)
  1332.         ;
  1333. #endif
  1334.         
  1335.     }    /* static void purgeline (void) */
  1336.  
  1337.  
  1338. /****************************************************************************
  1339. *    _canit                                                                     *
  1340. *    Send cancel string to get the other end to shut up.                        *
  1341. ****************************************************************************/
  1342.  
  1343. void _canit (void)
  1344.     {
  1345.     int result;
  1346.     int count = 0;
  1347. #ifdef    DEBUGZ
  1348.     char buf[128];
  1349. #endif
  1350.  
  1351.     static unsigned char canistr[] = { 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
  1352.                                        8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0 };
  1353.  
  1354.     _flushmo ();
  1355.     while (count != strlen ((char *) canistr))
  1356.         {
  1357.         while ((result = _send (canistr + count,
  1358.                                 strlen ((char *) canistr) - count)) == 0)
  1359.             ;
  1360.  
  1361.         count += result;
  1362. #ifdef    DEBUGZ
  1363.         sprintf (buf, "_canit: count = %d\r\n", count);
  1364.         _tout (buf);
  1365. #endif
  1366.         }
  1367.  
  1368.     _flushmo ();
  1369.     }    /* void _canit (void) */
  1370.  
  1371.  
  1372. /****************************************************************************
  1373. *    _zperr_                                                                    *
  1374. *    Log an error.                                                            *
  1375. ****************************************************************************/
  1376.  
  1377. void _zperr_ (char *s, ...)
  1378.     {
  1379.     va_list parms;
  1380.     char buf0[128];                            /* for report string            */
  1381.     char buf1[128];
  1382.     char buf2[128];
  1383.     
  1384.     if (_Verbose <= 0)
  1385.         return;
  1386.  
  1387.     va_start (parms, s);
  1388.     sprintf (buf1, "Retry %d: ", _errors);
  1389.     vsprintf (buf2, s, parms);
  1390.     sprintf (buf0, "%s%s\n", buf1, buf2);
  1391.     (*_do_report) (2, buf0);                /* call reporter function        */
  1392.     va_end (parms);
  1393.     }    /* void _zperr_ (char *s, ...) */
  1394.  
  1395.  
  1396. /****************************************************************************
  1397. *    _zperr                                                                    *
  1398. *    Default progress report function.                                        *
  1399. ****************************************************************************/
  1400.  
  1401. void _zperr (int type, void *data)
  1402.     {
  1403.     switch (type)
  1404.         {
  1405.         case 0:                                /* filename                        */
  1406.             tprintf ("FILE: %s\n", data);
  1407.             break;
  1408.  
  1409.         case 1:                                /* bytes transferred            */
  1410.             tprintf ("\r%7ld ", *((long *) data));
  1411.             break;
  1412.  
  1413.         case 2:                                /* other text                    */
  1414.             tprintf ("%s", data);
  1415.             break;
  1416.  
  1417.         case 3:                                /* end of transfer                */
  1418.             tprintf ("%5d files transferred\n", *((int *) data));
  1419.             break;
  1420.             
  1421.         default:
  1422.             return;
  1423.         }    /* switch (type) */
  1424.  
  1425.     }    /* void _zperr (int type, void *data) */
  1426.     
  1427.  
  1428. /****************************************************************************
  1429. *    _substr                                                                    *
  1430. *    Searches for <token> in string <s>.  Returns pointer to token within     *
  1431. *    string if found, NULL otherwise.                                        *
  1432. ****************************************************************************/
  1433.  
  1434. char *_substr (char *s, char *t)
  1435.     {
  1436.     char *ss,*tt;
  1437.     
  1438.     /* search for first char of token */
  1439.     
  1440.     for (ss = s; *s; s++)
  1441.         {
  1442.         if (*s == *t)
  1443.             {
  1444.             /* compare token with substring */
  1445.             
  1446.             for (ss = s, tt = t;;)
  1447.                 {
  1448.                 if (*tt == 0)
  1449.                     return s;
  1450.                     
  1451.                 if (*ss++ != *tt++)
  1452.                     break;
  1453.                     
  1454.                 }
  1455.  
  1456.             }    /* if (*s == *t) */
  1457.  
  1458.         }    /* for (ss = s; *s; s++) */
  1459.         
  1460.     return NULL;
  1461.     }    /* char *_substr (char *s, char *t) */
  1462.  
  1463.  
  1464. /****************************************************************************
  1465. *    getzrxinit                                                                *
  1466. *    Get the receiver's init parameters.                                        *
  1467. ****************************************************************************/
  1468.  
  1469. static int getzrxinit (void)
  1470.     {
  1471.     int n;
  1472.     struct stat f;
  1473.  
  1474.     for (n = 10; --n >= 0;)
  1475.         {
  1476.         switch (_zgethdr (_Rxhdr, 1))
  1477.             {
  1478.             case ZCHALLENGE:     /* Echo receiver's challenge numbr */
  1479.                 _stohdr (_Rxpos);
  1480.                 _zshhdr (ZACK, _Txhdr);
  1481.                 continue;
  1482.                 
  1483.             case ZCOMMAND:             /* They didn't see out ZRQINIT */
  1484.                 _stohdr (0L);
  1485.                 _zshhdr (ZRQINIT, _Txhdr);
  1486.                 continue;
  1487.                 
  1488.             case ZRINIT:
  1489.                 Rxflags = 0377 & _Rxhdr[ZF0];
  1490.                 _Txfcs32 = (Wantfcs32 && (Rxflags & CANFC32));
  1491.                 _Zctlesc |= Rxflags & TESCCTL;
  1492.                 Rxbuflen = (0377 & _Rxhdr[ZP0]) + ((0377 & _Rxhdr[ZP1]) << 8);
  1493.                 _vfile ("Rxbuflen=%d Tframlen=%d", Rxbuflen, Tframlen);
  1494. #if    0
  1495.                 signal (SIGINT, SIG_IGN);
  1496. #endif
  1497.  
  1498.                 /* Override to force shorter frame length */
  1499.     
  1500.                 if (Rxbuflen && (Rxbuflen > Tframlen) && (Tframlen >= 32))
  1501.                     Rxbuflen = Tframlen;
  1502.  
  1503.                 if (!Rxbuflen && (Tframlen >= 32) && (Tframlen <= 1024))
  1504.                     Rxbuflen = Tframlen;
  1505.  
  1506.                 _vfile ("Rxbuflen=%d", Rxbuflen);
  1507.  
  1508.                 /*
  1509.                  * If input is not a regular file, force ACK's each 1024
  1510.                  *  (A smarter strategey could be used here ...)
  1511.                  */
  1512.  
  1513.                 fstat (in, &f);
  1514.                 if (((f.st_mode & S_IFMT) != S_IFREG) &&
  1515.                     (Rxbuflen == 0 || Rxbuflen > 1024))
  1516.                     Rxbuflen = 1024;
  1517.  
  1518.                 _vfile ("Rxbuflen=%d", Rxbuflen);
  1519.  
  1520.                 return (sendzsinit ());
  1521.  
  1522.             case ZCAN:
  1523.             case ZTIMEOUT:
  1524.                 return ERROR;
  1525.  
  1526.             case ZRQINIT:
  1527.                 if (_Rxhdr[ZF0] == ZCOMMAND)
  1528.                     continue;
  1529.  
  1530.             default:
  1531.                 _zshhdr (ZNAK, _Txhdr);
  1532.                 continue;
  1533.             }    /* switch (_zgethdr (_Rxhdr, 1)) */
  1534.             
  1535.         }    /* for (n = 10; --n >= 0;) */
  1536.         
  1537.     return ERROR;
  1538.     }    /* static int getzrxinit (void) */
  1539.     
  1540.  
  1541. /****************************************************************************
  1542. *    sendzsinit                                                                *
  1543. *    Send send-init information.                                                *
  1544. ****************************************************************************/
  1545.  
  1546. static int sendzsinit (void)
  1547.     {
  1548.     int c;
  1549.  
  1550.     if (Myattn[0] == '\0' && (!_Zctlesc || (Rxflags & TESCCTL)))
  1551.         return OK;
  1552.         
  1553.     _errors = 0;
  1554.     for (;;)
  1555.         {
  1556.         _stohdr (0L);
  1557.         if (_Zctlesc)
  1558.             {
  1559.             _Txhdr[ZF0] |= TESCCTL;
  1560.             _zshhdr (ZSINIT, _Txhdr);
  1561.             }
  1562.         else
  1563.             _zsbhdr (ZSINIT, _Txhdr);
  1564.             
  1565.         _zsdata (Myattn, 1 + strlen (Myattn), ZCRCW);
  1566.         c = _zgethdr (_Rxhdr, 1);
  1567.         switch (c)
  1568.             {
  1569.             case ZCAN:
  1570.                 return ERROR;
  1571.  
  1572.             case ZACK:
  1573.                 return OK;
  1574.  
  1575.             default:
  1576.                 if (++_errors > 19)
  1577.                     return ERROR;
  1578.  
  1579.                 continue;
  1580.             }    /* switch (c) */
  1581.             
  1582.         }    /* for (;;) */
  1583.         
  1584.     }    /* static int sendzsinit (void) */
  1585.     
  1586.  
  1587. /****************************************************************************
  1588. *    zsendfile                                                                *
  1589. *    Send file name and related info.                                        *
  1590. ****************************************************************************/
  1591.  
  1592. static int zsendfile (char *buf, int blen)
  1593.     {
  1594.     int c;
  1595.  
  1596.     for (;;)
  1597.         {
  1598.         _Txhdr[ZF0] = Lzconv;                /* file conversion request */
  1599.         _Txhdr[ZF1] = _Lzmanag;                /* file management request */
  1600.         if (Lskipnocor)
  1601.             _Txhdr[ZF1] |= ZMSKNOLOC;
  1602.             
  1603.         _Txhdr[ZF2] = Lztrans;                /* file transport request */
  1604.         _Txhdr[ZF3] = 0;
  1605.         _zsbhdr (ZFILE, _Txhdr);
  1606.         _zsdata (buf, blen, ZCRCW);
  1607.  
  1608. again:
  1609.         c = _zgethdr (_Rxhdr, 1);
  1610.         switch (c)
  1611.             {
  1612.             case ZRINIT:
  1613.                 while ((c = readline (50)) > 0)
  1614.                     if (c == ZPAD)
  1615.                         {
  1616.                         goto again;
  1617.                         }
  1618.                         
  1619.                 /* **** FALL THRU TO **** */
  1620.  
  1621.             default:
  1622.                 continue;
  1623.  
  1624.             case ZCAN:
  1625.             case ZTIMEOUT:
  1626.             case ZABORT:
  1627.             case ZFIN:
  1628.                 return ERROR;
  1629.  
  1630.             case ZSKIP:
  1631.                 close (in);
  1632.                 return c;
  1633.                 
  1634.             case ZRPOS:
  1635.                 /*
  1636.                  * Suppress zcrcw request otherwise triggered by
  1637.                  * lastyunc==bytcnt
  1638.                  */
  1639.  
  1640.                 Lastsync = (bytcnt = _Txpos = _Rxpos) - 1;
  1641.                 lseek (in, _Rxpos, 0);
  1642.                 Dontread = FALSE;
  1643.                 return zsendfdata ();
  1644.             }    /* switch (c) */
  1645.             
  1646.         }    /* for (;;) */
  1647.         
  1648.     }    /* static int zsendfile (char *buf, int blen) */
  1649.     
  1650.  
  1651. /****************************************************************************
  1652. *    zsendfdata                                                                *
  1653. *    Send the data in the file.                                                *
  1654. ****************************************************************************/
  1655.  
  1656. static int zsendfdata (void)
  1657.     {
  1658.     int c, e, n;
  1659.     int newcnt;
  1660.     long tcount = 0;
  1661.     int junkcount;                    /* Counts garbage chars received by TX    */
  1662.     static int tleft = 6;            /* Counter for test mode                */
  1663.     int sent_zm = FALSE;            /* TRUE - sent ZMODEM string            */
  1664.     if (_Baud_z > 300)
  1665.         blklen = 256;
  1666.         
  1667.     if (_Baud_z > 1200)
  1668.         blklen = 512;
  1669.         
  1670.     if (_Baud_z > 2400)
  1671.         blklen = KSIZE;
  1672.         
  1673.     if (Rxbuflen && blklen > Rxbuflen)
  1674.         blklen = Rxbuflen;
  1675.         
  1676.     if (blkopt && blklen > blkopt)
  1677.         blklen = blkopt;
  1678.         
  1679.     _vfile ("Rxbuflen=%d blklen=%d", Rxbuflen, blklen);
  1680.     _vfile ("Txwindow = %u Txwspac = %d", Txwindow, Txwspac);
  1681.     Lrxpos = 0;
  1682.     junkcount = 0;
  1683.     Beenhereb4 = FALSE;
  1684.     
  1685. somemore:
  1686.     if (setjmp (intrjmp))
  1687.         {
  1688. waitack:
  1689.         junkcount = 0;
  1690.         c = getinsync (0);
  1691.  
  1692. gotack:
  1693.         switch (c)
  1694.             {
  1695.             default:
  1696.             case ZCAN:
  1697.                 close (in);
  1698.                 return ERROR;
  1699.  
  1700.             case ZSKIP:
  1701.                 close (in);
  1702.                 return c;
  1703.  
  1704.             case ZACK:
  1705.             case ZRPOS:
  1706.                 break;
  1707.  
  1708.             case ZRINIT:
  1709.                 return OK;
  1710.             }    /* switch (c) */
  1711.             
  1712.         /*
  1713.          * If the reverse channel can be tested for data,
  1714.          *  this logic may be used to detect error packets
  1715.          *  sent by the receiver, in place of setjmp/longjmp
  1716.          *  _rdchk () returns non 0 if a character is available
  1717.          */
  1718.  
  1719.         while (_rdchk ())
  1720.             {
  1721.             switch (readline (1))
  1722.                 {
  1723.                 case CAN:
  1724.                 case ZPAD:
  1725.                     c = getinsync (1);
  1726.                     goto gotack;
  1727.  
  1728.                 case XOFF:                /* Wait a while for an XON             */
  1729.                 case XOFF | 0200:
  1730.                     readline(100);
  1731.                 }    /* switch (readline (1)) */
  1732.                 
  1733.             }    /* while (_rdchk ()) */
  1734.             
  1735.         }    /* if (setjmp (intrjmp)) */
  1736.  
  1737. #if    0
  1738.     signal (SIGINT, onintr);
  1739. #endif
  1740.     newcnt = Rxbuflen;
  1741.     Txwcnt = 0;
  1742.     _stohdr (_Txpos);
  1743.     _zsbhdr (ZDATA, _Txhdr);
  1744.  
  1745.     /*
  1746.      * Special testing mode.  This should force receiver to Attn,ZRPOS
  1747.      *  many times.  Each time the signal should be caught, causing the
  1748.      *  file to be started over from the beginning.
  1749.      */
  1750.      
  1751.     if (Testattn)
  1752.         {
  1753.         if (--tleft)
  1754.             while (tcount < 20000)
  1755.                 {
  1756.                 _send ((unsigned char *) qbf, strlen (qbf));
  1757.                 tcount += strlen (qbf);
  1758.                 while (_rdchk ())
  1759.                     {
  1760.                     switch (readline (1))
  1761.                         {
  1762.                         case CAN:
  1763.                         case ZPAD:
  1764.                             goto waitack;
  1765.  
  1766.                         case XOFF:        /* Wait for XON                     */
  1767.                         case XOFF | 0200:
  1768.                             readline (100);
  1769.                         }    /* switch (readline (1)) */
  1770.                         
  1771.                     }    /* while (_rdchk ()) */
  1772.                     
  1773.                 }    /* while (tcount < 20000) */
  1774.                 
  1775. #if    0
  1776.         signal (SIGINT, SIG_IGN);
  1777. #endif
  1778.         _canit ();
  1779.         sleep (3);
  1780.         purgeline ();
  1781.         printf ("\nTcount = %ld\n", tcount);
  1782.         if (tleft)
  1783.             {
  1784.             printf ("ERROR: Interrupts Not Caught\n");
  1785.             return (ERROR);
  1786.             }
  1787.             
  1788.         return (0);
  1789.         }    /* if (Testattn) */
  1790.         
  1791.     do
  1792.         {
  1793.         if (Dontread)
  1794.             {
  1795.             n = Lastn;
  1796.             }
  1797.         else
  1798.             {
  1799.             n = zfilbuf (txbuf, blklen);
  1800.             Lastread = _Txpos;
  1801.             Lastn = n;
  1802.             }
  1803.  
  1804.         Dontread = FALSE;
  1805.         if (n < blklen)
  1806.             e = ZCRCE;
  1807.         else if (junkcount > 3)
  1808.             e = ZCRCW;
  1809.         else if (bytcnt == Lastsync)
  1810.             e = ZCRCW;
  1811.         else if (Rxbuflen && (newcnt -= n) <= 0)
  1812.             e = ZCRCW;
  1813.         else if (Txwindow && (Txwcnt += n) >= Txwspac)
  1814.             {
  1815.             Txwcnt = 0;
  1816.             e = ZCRCQ;
  1817.             }
  1818.         else
  1819.             e = ZCRCG;
  1820.             
  1821.         if (_Verbose > 1)
  1822.             {
  1823.             (*_do_report) (1, &_Txpos);
  1824.             if (!sent_zm)
  1825.                 {
  1826.                 sent_zm = TRUE;
  1827.                 _say ("ZMODEM%s", _Crc32t ? " CRC-32" : "");
  1828.                 }
  1829.                 
  1830.             }
  1831.                      
  1832.         _zsdata (txbuf, n, e);
  1833.         bytcnt = _Txpos += n;
  1834.         if (e == ZCRCW)
  1835.             goto waitack;
  1836.  
  1837.         /*
  1838.          * If the reverse channel can be tested for data,
  1839.          *  this logic may be used to detect error packets
  1840.          *  sent by the receiver, in place of setjmp/longjmp
  1841.          *  _rdchk () returns non 0 if a character is available
  1842.          */
  1843.          
  1844.         while (_rdchk ())
  1845.             {
  1846.             switch (readline (1))
  1847.                 {
  1848.                 case CAN:
  1849.                 case ZPAD:
  1850.                     c = getinsync (1);
  1851.                     if (c == ZACK)
  1852.                         break;
  1853.  
  1854.                     /* zcrce - dinna wanna starta ping-pong game */
  1855.  
  1856.                     _zsdata (txbuf, 0, ZCRCE);
  1857.                     goto gotack;
  1858.  
  1859.                 case XOFF:                /* Wait a while for an XON             */
  1860.                 case XOFF | 0200:
  1861.                     readline (100);
  1862.  
  1863.                 default:
  1864.                     ++junkcount;
  1865.                 }    /* switch (readline (1)) */
  1866.                 
  1867.             }    /* while (_rdchk ()) */
  1868.             
  1869.         if (Txwindow)
  1870.             {
  1871.             while ((tcount = _Txpos - Lrxpos) >= Txwindow)
  1872.                 {
  1873.                 _vfile ("%ld window >= %u", tcount, Txwindow);
  1874.                 if (e != ZCRCQ)
  1875.                     _zsdata (txbuf, 0, e = ZCRCQ);
  1876.                     
  1877.                 c = getinsync (1);
  1878.                 if (c != ZACK)
  1879.                     {
  1880.                     _zsdata (txbuf, 0, ZCRCE);
  1881.                     goto gotack;
  1882.                     }
  1883.                 }
  1884.  
  1885.             _vfile ("window = %ld", tcount);
  1886.             }
  1887.  
  1888.         } while (n == blklen);
  1889.  
  1890. #if    0
  1891.     signal (SIGINT, SIG_IGN);
  1892. #endif
  1893.  
  1894.     for (;;)
  1895.         {
  1896.         _stohdr (_Txpos);
  1897.         _zsbhdr (ZEOF, _Txhdr);
  1898.         switch (getinsync (0))
  1899.             {
  1900.             case ZACK:
  1901.                 continue;
  1902.  
  1903.             case ZRPOS:
  1904.                 goto somemore;
  1905.  
  1906.             case ZRINIT:
  1907.                 return OK;
  1908.  
  1909.             case ZSKIP:
  1910.                 close (in);
  1911.                 return c;
  1912.  
  1913.             default:
  1914.                 close (in);
  1915.                 return ERROR;
  1916.             }    /* switch (getinsync (0)) */
  1917.             
  1918.         }    /* for (;;) */
  1919.         
  1920.     }    /* static int zsendfdata (void) */
  1921.     
  1922.  
  1923. /****************************************************************************
  1924. *    getinsync                                                                *
  1925. *    Respond to receiver's complaint, get back in sync with receiver.        *
  1926. ****************************************************************************/
  1927.  
  1928. static int getinsync (int flag)
  1929.     {
  1930.     int c;
  1931.  
  1932.     for (;;)
  1933.         {
  1934.         if (Testattn)
  1935.             {
  1936.             printf ("\r\n\n\n***** Signal Caught *****\r\n");
  1937.             _Rxpos = 0;
  1938.             c = ZRPOS;
  1939.             }
  1940.         else
  1941.             c = _zgethdr (_Rxhdr, 0);
  1942.             
  1943.         switch (c)
  1944.             {
  1945.             case ZCAN:
  1946.             case ZABORT:
  1947.             case ZFIN:
  1948.             case ZTIMEOUT:
  1949.                 return ERROR;
  1950.  
  1951.             case ZRPOS:
  1952.                 /* ************************************* */
  1953.                 /*    If sending to a modem buffer, you     */
  1954.                 /*     might send a break at this point to */
  1955.                 /*     dump the modem's buffer.             */
  1956.  
  1957.                 if (Lastn >= 0 && Lastread == _Rxpos)
  1958.                     {
  1959.                     Dontread = TRUE;
  1960.                     }
  1961.                 else
  1962.                     {
  1963. #if    0
  1964.                     clearerr (in);           /* In case file EOF seen */
  1965. #endif
  1966.                     lseek (in, _Rxpos, 0);
  1967.                     }
  1968.  
  1969.                 bytcnt = Lrxpos = _Txpos = _Rxpos;
  1970.                 if (Lastsync == _Rxpos)
  1971.                     {
  1972.                     if (++Beenhereb4 > 4)
  1973.                         if (blklen > 256)
  1974.                             blklen /= 2;
  1975.  
  1976.                     }
  1977.  
  1978.                 Lastsync = _Rxpos;
  1979.                 return c;
  1980.  
  1981.             case ZACK:
  1982.                 Lrxpos = _Rxpos;
  1983.                 if (flag || _Txpos == _Rxpos)
  1984.                     return ZACK;
  1985.  
  1986.                 continue;
  1987.  
  1988.             case ZRINIT:
  1989.             case ZSKIP:
  1990.                 close (in);
  1991.                 return c;
  1992.  
  1993.             case ERROR:
  1994.             default:
  1995.                 _zsbhdr (ZNAK, _Txhdr);
  1996.                 continue;
  1997.             }    /* switch (c) */
  1998.             
  1999.         }    /* for (;;) */
  2000.         
  2001.     }    /* static int getinsync (int flag) */
  2002.     
  2003.  
  2004. /****************************************************************************
  2005. *    saybibi                                                                    *
  2006. *    Say "bibi" to the receiver, try to do it cleanly.                        *
  2007. ****************************************************************************/
  2008.  
  2009. static void saybibi (void)
  2010.     {
  2011.     for (;;)
  2012.         {
  2013.         _stohdr (0L);                      /* CAF Was _zsbhdr - minor change */
  2014.         _zshhdr (ZFIN, _Txhdr);                /*    to make debugging easier */
  2015.         switch (_zgethdr (_Rxhdr, 0))
  2016.             {
  2017.             case ZFIN:
  2018.                 _sendline ('O');
  2019.                 _sendline ('O');
  2020.                 _flushmo ();
  2021.                 
  2022.             case ZCAN:
  2023.             case ZTIMEOUT:
  2024.                 return;
  2025.             }
  2026.  
  2027.         }
  2028.  
  2029.     }    /* static void saybibi (void) */
  2030.  
  2031.  
  2032. /****************************************************************************
  2033. *    _bttyout                                                                *
  2034. *    Local screen character display function.                                *
  2035. ****************************************************************************/
  2036.     
  2037. void _bttyout (int c)
  2038.     {
  2039.     char str[2];                        /* for making string                */
  2040.     
  2041.     if (_Verbose)
  2042.         {
  2043.         str[0] = (char) c;
  2044.         str[1] = '\0';
  2045.         _say (str);
  2046.         }
  2047.         
  2048.     }    /* void _bttyout (int c) */
  2049.  
  2050.  
  2051. /****************************************************************************
  2052. *    zsendcmd                                                                *
  2053. *    Send command and related info.                                            *
  2054. ****************************************************************************/
  2055.  
  2056. static int zsendcmd (char *buf, int blen)
  2057.     {
  2058.     int c;
  2059.     long cmdnum;
  2060.  
  2061.     cmdnum = getpid ();
  2062.     _errors = 0;
  2063.     for (;;)
  2064.         {
  2065.         _stohdr (cmdnum);
  2066.         _Txhdr[ZF0] = (char) Cmdack1;
  2067.         _zsbhdr (ZCOMMAND, _Txhdr);
  2068.         _zsdata (buf, blen, ZCRCW);
  2069.  
  2070. listen:
  2071.         _Rxtimeout = 100;                   /* Ten second wait for resp. */
  2072.         c = _zgethdr (_Rxhdr, 1);
  2073.  
  2074.         switch (c)
  2075.             {
  2076.             case ZRINIT:
  2077.                 goto listen;    /* CAF 8-21-87 */
  2078.  
  2079.             case ERROR:
  2080.             case ZTIMEOUT:
  2081.                 if (++_errors > Cmdtries)
  2082.                     return ERROR;
  2083.  
  2084.                 continue;
  2085.  
  2086.             case ZCAN:
  2087.             case ZABORT:
  2088.             case ZFIN:
  2089.             case ZSKIP:
  2090.             case ZRPOS:
  2091.                 return ERROR;
  2092.  
  2093.             default:
  2094.                 if (++_errors > 20)
  2095.                     return ERROR;
  2096.  
  2097.                 continue;
  2098.  
  2099.             case ZCOMPL:
  2100.                 Exitcode = (int) _Rxpos;
  2101.                 saybibi ();
  2102.                 return OK;
  2103.             }    /* switch (c) */
  2104.             
  2105.         }    /* for (;;) */
  2106.         
  2107.     }    /* static int zsendcmd (char *buf, int blen) */
  2108.     
  2109.  
  2110. /****************************************************************************
  2111. *    chkinvok                                                                *
  2112. *    Set chosen protocol.                                                    *
  2113. ****************************************************************************/
  2114.  
  2115. static void chkinvok (char protocol)
  2116.     {
  2117.     if (protocol == 'y')
  2118.         {
  2119.         _Nozmodem = TRUE;
  2120.         blklen = KSIZE;
  2121.         }
  2122.         
  2123.     if (protocol == 'x')
  2124.         {
  2125.         Modem2 = TRUE;
  2126.         }
  2127.  
  2128.     }    /* static void chkinvok (char protocol) */
  2129. /* End of sz.c */
  2130.